import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:flutter_flavor/flutter_flavor.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:path_provider/path_provider.dart';

class OssHelper {
  static String ossScheme = "https://";

  static final uploadFileRoot = FlavorConfig.instance.variables["ossUploadFileRoot"];

  static String pictureBaseUrl=FlavorConfig.instance.variables["pictureBaseUrl"];

  static String endpoint = FlavorConfig.instance.variables["ossEndpoint"];

  static String ossUrl = ossScheme + FlavorConfig.instance.variables["ossDomain"] + FlavorConfig.instance.variables["ossPath"];

  static String appCode = FlavorConfig.instance.variables["ossAppCode"];

  static Future<Response> getOssConfiguration() async {
    try {
      Response response;
      Options options = Options();

      String randomString = OssUtil().getRandom(10);
      options.headers = {
        "Authorization": appCode,
        "X-Ca-Nonce": randomString,
      };
      response = await Dio().get(ossUrl, options: options);
      return response;
    } catch (e) {
      print(e);
    }
  }

  static Future<String> uploadImage(File file) async {
    OssHelper.getOssConfiguration().then((result) {
      Map<String, dynamic> ossMsg = {
        "accessKeyId": result.data['data']['accessKeyId'],
        "accessKeySecret": result.data['data']['accessKeySecret'],
        "expiration": result.data['data']['expiration'],
        "securityToken": result.data['data']['securityToken']
      };
      OssHelper.uploadToOss(file, ossMsg).then((value) {
        return value;
      });
    });
  }

  static Future<String> uploadToOss(
      File file, Map<String, dynamic> data) async {
    Directory tempDir = await getTemporaryDirectory();
    String tempPath = tempDir.path;
    final targetPath =tempPath+ "/${DateTime.now().millisecond}.jpg";
    var result = await FlutterImageCompress.compressAndGetFile(
      file.absolute.path,
      targetPath,
      quality: 88,
      rotate: 180,
    );

    var key = OssUtil.instance.getImageUploadName(
        uploadFileRoot, OssUtil.instance.getImageName(result.path));
    FormData formData = FormData.fromMap({
      'Filename': OssUtil.instance.getImageName(file.path),
      //"可以填写文件夹名（对应于oss服务中的文件夹）/" + fileName
      'key': key,
      //上传后的文件名
      'policy': OssUtil.policy,
      //Bucket 拥有者的AccessKeyId。
      'OSSAccessKeyId': data['accessKeyId'],
      //  accessKeyId 大小写 和服务端返回的对应就成，不要在意这些细节  下同
      //让服务端返回200，不然，默认会返回204
      'success_action_status': '200',
      'signature': OssUtil.instance.getSignature(data['accessKeySecret']),
      //临时用户授权时必须，需要携带后台返回的security-token
      'x-oss-security-token': data['securityToken'],
      'file': MultipartFile.fromFileSync(file.path,
          filename: OssUtil.instance.getImageNameByPath(file.path))
    });

    print(formData.fields);
    //然后通过存储地址直接把表单(formdata)上传上去;
    Dio dio = Dio();
    dio.options.responseType = ResponseType.plain;
    Response response = await dio.post(endpoint, data: formData);
    if (response.statusCode == 200) {
      var url = endpoint + key;
      // print(response.headers);
      // print(url);
      print("上传成功");
      return url;
    } else {
      print("错误");
      return "";
    }
  }
}

class OssUtil {
  //验证文本域
  static String _policyText =
      '{"expiration": "2069-05-22T03:15:00.000Z","conditions": [["content-length-range", 0, 1048576000]]}'; //UTC时间+8=北京时间

  //进行utf8编码
  // ignore: non_constant_identifier_names
  static List<int> _policyText_utf8 = utf8.encode(_policyText);

  //进行base64编码
  static String policy = base64.encode(_policyText_utf8);

  //再次进行utf8编码
  // ignore: non_constant_identifier_names
  static List<int> _policy_utf8 = utf8.encode(policy);

  // 工厂模式
  factory OssUtil() => _getInstance();

  static OssUtil get instance => _getInstance();
  static OssUtil _instance;

  OssUtil._internal();

  static OssUtil _getInstance() {
    if (_instance == null) {
      _instance = new OssUtil._internal();
    }
    return _instance;
  }

  /*
  *获取signature签名参数
  */
  String getSignature(String _accessKeySecret) {
    //进行utf8 编码
    // ignore: non_constant_identifier_names
    print(_accessKeySecret);
    List<int> AccessKeySecretUtf8 = utf8.encode(_accessKeySecret);
    //通过hmac,使用sha1进行加密
    List<int> signaturePre =
        new Hmac(sha1, AccessKeySecretUtf8).convert(_policy_utf8).bytes;
    //最后一步，将上述所得进行base64 编码
    String signature = base64.encode(signaturePre);
    return signature;
  }

  // ignore: slash_for_doc_comments
  /**
   * 生成上传上传图片的名称 ,获得的格式:photo/20171027175940_oCiobK
   * 可以定义上传的路径uploadPath(Oss中保存文件夹的名称)
   * @param uploadPath 上传的路径 如：/photo
   * @return photo/20171027175940_oCiobK
   */
  String getImageUploadName(String uploadPath, String filePath) {
    String imageMame = "";
    var timestamp = new DateTime.now().millisecondsSinceEpoch;
    imageMame = timestamp.toString() + "_" + getRandom(6);
    if (uploadPath != null && uploadPath.isNotEmpty) {
      imageMame = uploadPath + imageMame;
    }
    String imageType =
        filePath?.substring(filePath?.lastIndexOf("."), filePath?.length);
    return imageMame + imageType;
  }

  String getImageName(String filePath) {
    String imageMame = "";
    var timestamp = new DateTime.now().millisecondsSinceEpoch;
    imageMame = timestamp.toString() + "_" + getRandom(6);
    String imageType =
        filePath?.substring(filePath?.lastIndexOf("."), filePath?.length);
    return imageMame + imageType;
  }

  /*
  * 生成固定长度的随机字符串
  * */
  String getRandom(int num) {
    String alphabet = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';
    String left = '';
    for (var i = 0; i < num; i++) {
//    right = right + (min + (Random().nextInt(max - min))).toString();
      left = left + alphabet[Random().nextInt(alphabet.length)];
    }
    return left;
  }

  /*
  * 根据图片本地路径获取图片名称
  * */
  String getImageNameByPath(String filePath) {
    // ignore: null_aware_before_operator
    return filePath?.substring(
        filePath?.lastIndexOf("/") + 1, filePath?.length);
  }
}
